use std::io::ErrorKind;
use std::io::Write;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::fs;

const PORT: &str = "3527";

const CMD_TYPE_CONN: i32 = 0;
const CMD_TYPE_BC: i32 = 3;
const CMD_TYPE_SCREEN: i32 = 4;

fn connect_pqa<'a>(pqa : &UdpSocket) -> String {
    let master_cmd: [u8; 12] = unsafe {
        let mut result = std::mem::MaybeUninit::zeroed();
        let dest = result.as_mut_ptr() as *mut u8;
        let mut idx = 0;
        let t: i32 = CMD_TYPE_CONN;
        std::ptr::copy_nonoverlapping(t.to_le_bytes().as_ptr(), dest, t.to_le_bytes().len());
        idx += t.to_le_bytes().len();
        let l: i32 = 4;
        std::ptr::copy_nonoverlapping(l.to_le_bytes().as_ptr(), dest.add(idx), l.to_le_bytes().len());
        idx += l.to_le_bytes().len();
        let v: i32 = 0;
        std::ptr::copy_nonoverlapping(v.to_le_bytes().as_ptr(), dest.add(idx), v.to_le_bytes().len());
        
        result.assume_init()
    };

    let ok = pqa.send(&master_cmd);
    match ok {
        Ok(_o) => {},
        Err(_e) => {
            println!("ConnectionError: {}", _e);
            return String::new();
        },
    }

    let mut size = 0;
    let mut data: [u8; 2048] = [0; 2048];
    let ok = pqa.recv(&mut data);
    match ok {
        Ok(_size) => {size = _size;},
        Err(_e) => {
            println!("ConnectionError: {}", _e);
            return String::new();
        },
    }

    let t = <i32>::from_le_bytes(data[..4].try_into().unwrap());
    if t == CMD_TYPE_CONN {
        let mut name = String::from("");
        let n = &data[8..size];
        let na = std::str::from_utf8(n).unwrap();
        let inx = na.find('\0');
        match inx {
            Some(_i) => {name = String::from(&na[.._i]);},//std::str::from_utf8(&data[8..(8+_i)]).unwrap()
            None => {}
        }
        println!("name: {:#?}", name);

        return name;
    }
    return String::new();
}

fn get_pqa_screen(pqa : &UdpSocket, name: &String) -> bool {
    let master_cmd: [u8; 12] = unsafe {
        let mut result = std::mem::MaybeUninit::zeroed();
        let dest = result.as_mut_ptr() as *mut u8;
        let mut idx = 0;
        let t: i32 = CMD_TYPE_SCREEN;
        std::ptr::copy_nonoverlapping(t.to_le_bytes().as_ptr(), dest, t.to_le_bytes().len());
        idx += t.to_le_bytes().len();
        let l: i32 = 4;
        std::ptr::copy_nonoverlapping(l.to_le_bytes().as_ptr(), dest.add(idx), l.to_le_bytes().len());
        idx += l.to_le_bytes().len();
        let v: i32 = 0;
        std::ptr::copy_nonoverlapping(v.to_le_bytes().as_ptr(), dest.add(idx), v.to_le_bytes().len());
        
        result.assume_init()
    };

    let ok = pqa.send(&master_cmd);
    match ok {
        Ok(_o) => {},
        Err(_e) => {
            println!("ConnectionError: {}", _e);
            return false;
        },
    }

    let mut size = 0;
    let mut data = [0; 2048];
    let ok = pqa.recv(&mut data);
    match ok {
        Ok(_size) => {size = _size;},
        Err(_e) => {
            println!("ConnectionError: {}", _e);
            return false;
        },
    }

    let t = <i32>::from_le_bytes(data[..4].try_into().unwrap());
    let sz = <u32>::from_le_bytes(data[4..8].try_into().unwrap()) as usize;
    println!("{} : {}", t, sz);
    if t == CMD_TYPE_SCREEN {
        let mut bmp = fs::File::create(name).unwrap();
        bmp.write(&data[8..]).unwrap();
        let mut rd = data[8..].len();
        loop {
            let mut data = [0; 2048];
            let ok = pqa.recv(&mut data);
            match ok {
                Ok(_size) => {
                    bmp.write(&data[.._size]).unwrap();
                    rd += _size;
                    if rd >= sz {
                        break;
                    }
                },
                Err(_e) => {
                    println!("ConnectionError: {}", _e);
                    break;
                },
            }
        }
        return true;
    }

    return false;
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let argc = args.len();

    let mut host_addr = String::from("127.0.0.1");
    if argc > 1 {
        let addr = String::from(args[1].clone()) + ":" + PORT;
        host_addr = addr;
    } else {
        host_addr += ":";
        host_addr += PORT;
    }
    println!("Hello, {}!", host_addr);

    let pqa_client = UdpSocket::bind("0.0.0.0:0").unwrap();

    pqa_client.connect(host_addr).unwrap();

    let mut pqa_name = String::new();
    pqa_name = connect_pqa(&pqa_client);
    if pqa_name.is_empty() == false {
        println!("Connected.");
        let ok = get_pqa_screen(&pqa_client, &pqa_name);
        if ok == true {
            println!("Get Screen Ok.");
        }
    } else {
        println!("Unknown Device!");
    }

}
